// AlbumsTab.cpp : implementation file
//

#include "stdafx.h"
#include "moretunes.h"
#include "AlbumsTab.h"
#include "misc.h"
#include ".\albumstab.h"
#include "shareware.h"

// Lists columns
#define SONG_LIST_COL1								"#"
#define SONG_LIST_COL2								"Song title"
#define SONG_LIST_COL3								"In Playlist"

#define	SONG_LIST_COL1_SIZE							40
#define	SONG_LIST_COL2_SIZE							330
#define	SONG_LIST_COL3_SIZE							63

#define ALBUM_LIST_COL1								"Album"
#define ALBUM_LIST_COL2								"Artist"
#define ALBUM_LIST_COL3								"Tracks"
#define ALBUM_LIST_COL4								"Year"

#define	ALBUM_LIST_COL1_SIZE						200
#define	ALBUM_LIST_COL2_SIZE						130
#define	ALBUM_LIST_COL3_SIZE						50
#define	ALBUM_LIST_COL4_SIZE						53


// Labels names
#define LABEL_ARTIST_NAME								"Play a music or search something"
#define LABEL_YEAR_NAME									"Release Date: "
#define LABEL_NB_TRACKS_NAME							"Number of tracks: "
#define LABEL_PRICE_NAME								"Price: "
#define LABEL_RATING_NAME								"Rating: "
#define LABEL_GENRE_NAME								"Genre: "

#define NOT_FOUND "moreTunes can't find this artist."

// CAlbumsTab dialog

IMPLEMENT_DYNAMIC(CAlbumsTab, CResizablePage)
CAlbumsTab::CAlbumsTab(CAllTabs* allTabs, CCoverTab *coverTab, CReviewsTab *reviewTab, CPrefTab *prefs, CID3Tab *id3Tab)
: CResizablePage(CAlbumsTab::IDD)
, _searching(FALSE)
, _refresh(TRUE)
, _searchResult(0)
,_currentAlbum(0)
,_prefs(prefs)
, _ID3Tab(id3Tab)
, _proposalAlbum(NULL)
, _miniWnd(NULL, allTabs, prefs)
{
	_allTabs = allTabs;
	_coverTab = coverTab;
	_reviewTab = reviewTab;
}

CAlbumsTab::~CAlbumsTab()
{
}
BOOL CAlbumsTab::OnInitDialog()
{
	CWnd* pMainWnd = AfxGetMainWnd();
	CResizablePage::OnInitDialog();
	// List settings
	_trackList.InsertColumn(0, SONG_LIST_COL1, LVCFMT_LEFT, SONG_LIST_COL1_SIZE);
	_trackList.InsertColumn(1, SONG_LIST_COL2, LVCFMT_LEFT, SONG_LIST_COL2_SIZE);
	_trackList.InsertColumn(2, SONG_LIST_COL3, LVCFMT_LEFT, SONG_LIST_COL3_SIZE);
	_trackList.SetExtendedStyle(LVS_EX_FULLROWSELECT|LVS_EX_ONECLICKACTIVATE|LVS_EX_UNDERLINEHOT);

	_albumList.InsertColumn(0, ALBUM_LIST_COL1, LVCFMT_LEFT, ALBUM_LIST_COL1_SIZE);
	_albumList.InsertColumn(1, ALBUM_LIST_COL2, LVCFMT_LEFT, ALBUM_LIST_COL2_SIZE);
	_albumList.InsertColumn(2, ALBUM_LIST_COL3, LVCFMT_LEFT, ALBUM_LIST_COL3_SIZE);
	_albumList.InsertColumn(3, ALBUM_LIST_COL4, LVCFMT_LEFT, ALBUM_LIST_COL4_SIZE);
	_albumList.SetExtendedStyle(LVS_EX_FULLROWSELECT|LVS_EX_ONECLICKACTIVATE|LVS_EX_UNDERLINEHOT);
	_albumList._listAlbum = TRUE;

	// Special Font for title
	CFont font;
	LOGFONT lf;
	memset(&lf, 0, sizeof(LOGFONT));
	lf.lfHeight = 16;
	strcpy(lf.lfFaceName, "Arial");
	VERIFY(font.CreateFontIndirect(&lf));
	_artist.SetFont(&font);

	// Misc
	SetTimer(0, 1500, NULL);
	displayAlbum();

	// moreTunes mini
	BOOL ret = _miniWnd.Create(IDD_MINI);
	if(!ret)   //Create failed.
		AfxMessageBox("Error creating Dialog");
	CRect fullRect;
	_miniWnd.GetWindowRect(fullRect); // absolute position
	if (_prefs->_miniLeft >= 0 && _prefs->_miniTop >= 0)
		_miniWnd.SetWindowPos(this, _prefs->_miniLeft, _prefs->_miniTop, 0, 0, SWP_NOZORDER|SWP_NOSIZE); // relative position
	else
		_miniWnd.SetWindowPos(this, 100, 100, 0, 0, SWP_NOZORDER|SWP_NOSIZE); // relative position

	return TRUE;  // return TRUE unless you set the focus to a control
}

/////////////////////////////////////////////////////////////////////////////////
// Buttons shits..
/////////////////////////////////////////////////////////////////////////////////

void CAlbumsTab::OnReload(void) {
	CString name;
	if (_currentAlbum != NULL)
		name = _currentAlbum->getArtist();
	else
		name = _ID3Tab->_artistData;
	if (name.IsEmpty())
		_editFind.GetWindowText(name);
	if (triggerDownload(name, TRUE)) {
		_editFind.SetSel(NULL, name.GetLength());
	}
}

BOOL CAlbumsTab::triggerDownload(CString name, BOOL reload, BOOL connect) {
	// Can we search and inits
	if (_searching)
		return FALSE;

	// We pass the name to alltabs which is the downloader
	if (!name.IsEmpty()) {
		_searching = TRUE;
		name.Replace("&", "and"); // amazon does not like the &
		_searchButton.SetWindowText(BUTTON_SEARCH_STOP);
		_allTabs->downloadAlbums(name, reload, connect);
		return TRUE;
	}
	return FALSE;
}

/////////////////////////////////////////////////////////////////////////////////
// Set the results
/////////////////////////////////////////////////////////////////////////////////

BOOL CAlbumsTab::setSearchReady(CList<Album*, Album*> *result) {
	// Cleaning the place
	_searching = FALSE;
	_searchButton.SetWindowText(BUTTON_SEARCH);
	setResult(result);
	_ID3Tab->Invalidate();
	_ID3Tab->UpdateWindow();
	if (_albumList.GetItemCount() != NULL) {
		CSize size;
		size.cx = 0;
		size.cy = -1000;
		_albumList.Scroll(size);
		_albumList.SortItems(MyCompareProcMatch, NULL);
	}
	if (result == NULL || result->IsEmpty()) {
		_artist.SetWindowText(NOT_FOUND);
	}
	return FALSE;
}

BOOL CAlbumsTab::setResult(CList<Album*, Album*> *result)
{
	// Set the new album list
	_searchResult = result;
	if (_searchResult == NULL || _searchResult->IsEmpty() == TRUE) {
		_proposalAlbum = NULL;
		setCurrentAlbum(NULL);
	}
	else if (_currentAlbum == NULL) {
		matchAlbum();
		selectProposal();
		setCurrentAlbum(_proposalAlbum);
	}
	else {
		matchAlbum();
		selectProposal();
		setCurrentAlbum(_currentAlbum);
	}

	// Display the changes
	displayList();
	return TRUE;
}

int CAlbumsTab::setCurrentAlbum(Album *album)
{
	_currentAlbum = album;
	if (_currentAlbum != NULL)
		_trackList._track = _currentAlbum->_matchTrack;

	// Loading the other tabs
	_coverTab->setResult(_currentAlbum);
	_reviewTab->setResult(_currentAlbum);
	_miniWnd.setResult(_currentAlbum);
	_ID3Tab->setProposal(_proposalAlbum);

	// Display the changes
	displayAlbum();
	return 0;
}

BOOL CAlbumsTab::displayAlbum(void)
{
	if (_currentAlbum == NULL) {
		clearAlbum();
		return FALSE;
	}

	// Loading the albums tab
	CString str;
	_artist.SetWindowText(_currentAlbum->getArtist()+" - "+_currentAlbum->getTitle());
	_date.SetWindowText(LABEL_YEAR_NAME+_currentAlbum->getDate());
	_rating.SetWindowText(LABEL_RATING_NAME+_currentAlbum->getAverageRating());
	_price.SetWindowText(LABEL_PRICE_NAME+_currentAlbum->getPrice());
	CString genre;
	genre = LABEL_GENRE_NAME+_currentAlbum->getGenre();
	genre.Replace("&", "&&");
	_genre.SetWindowText(genre);
	str.Format(TEXT("%d"), _currentAlbum->getTracksSize());
	_trackNum.SetWindowText(LABEL_NB_TRACKS_NAME+str);

	_pic.loadPic(_currentAlbum->getImageFile());
	Invalidate();

	if (!_trackList.DeleteAllItems())
		return FALSE;
	for (int i = 0; i < _currentAlbum->getTracksSize(); i++) {
		CString str;
		str.Format(TEXT("%d"), i + 1);
		_trackList.InsertItem(LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM,
			i, str, 0, LVIS_SELECTED, 0, (LPARAM) i);
//		_trackList.InsertItem(i, str);
		_trackList.SetItemText(i, 1, _currentAlbum->getTracks(i));
	}
	if (_prefs->_autoScanData == TRUE && _searching == FALSE)
		scanPlaylist();
	return TRUE;
}

#define PLAYLIST_MAX_SIZE 30

int CAlbumsTab::scanPlaylist(void) {
	if (_ID3Tab->_player == NULL || _currentAlbum == NULL
		|| _ID3Tab->FindPlayer() == NULL || _trackList.GetItemCount() == NULL)
		return NULL;
	int autoSearch = _prefs->_autoSearchData;
	_prefs->_autoSearchData = FALSE;
	int plPos = _ID3Tab->_player->PlGetPos();
	int size = _ID3Tab->_player->PlGetSize();
	int start = 0;
	if (size > PLAYLIST_MAX_SIZE) {
		if (plPos - PLAYLIST_MAX_SIZE / 2 >= 0)
			start = plPos - PLAYLIST_MAX_SIZE / 2;
		if (start + PLAYLIST_MAX_SIZE <= size)
			size = start + PLAYLIST_MAX_SIZE;
	}
	// Test the playlist
	for (int i = start; i < size; i++) {
		_ID3Tab->_player->PlSetPos(i);
		_ID3Tab->setResult(NULL);
		CString purifiedTitle = purifyName(_ID3Tab->getTitleName());
		if (_currentAlbum != NULL)
			for (int j = 0, len = _currentAlbum->getTracksSize(); j < len; j++) {
				if (purifiedTitle == purifyName(_currentAlbum->getTracks(j)))
					_trackList.SetItemText(j, 2, "Yes");
			}
	}
	// Back to normal
	_prefs->_autoSearchData = autoSearch;
	_ID3Tab->_player->PlSetPos(plPos);
	_ID3Tab->setResult(_currentAlbum);
	return 0;
}
//int listSize = 0;
BOOL CAlbumsTab::displayList(void) {
	static int listSize = 0;
	if (_currentAlbum == NULL) {
		_albumList.DeleteAllItems();
		listSize = 0;
		return FALSE;
	}
	if (_albumList.GetItemCount() != 0) {
		if (_albumList.GetItemData(_albumList.GetItemCount() - 1) == NULL) {
			_albumList.DeleteAllItems();
			listSize = 0;
		}
	}
	int i = listSize;
	if (_searchResult->GetCount() == i)
		return TRUE;

	POSITION pos = _searchResult->GetHeadPosition();
	Album *album;
	for (int j = _albumList.GetItemCount(); i < _searchResult->GetCount(); i++) {
		album = _searchResult->GetNext(pos);
		if (_allTabs->_similar == FALSE) {
			if (_prefs->_resultsData == TRUE && purifyName(album->getArtist()) != purifyName(_ID3Tab->_artistData))
				continue;
		}
		_albumList.InsertItem(LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM,
			j, album->getTitle(), 0, LVIS_SELECTED, 0, (LPARAM) album);
		_albumList.SetItemText(j, 1, album->getArtist());
		CString tNum;
		tNum.Format(TEXT("%d"), album->getTracksSize());
		if (tNum == "0")
			tNum = " ";
		_albumList.SetItemText(j, 2, tNum);
		_albumList.SetItemText(j, 3, album->getDateYear());
		j++;

	}
	listSize = (int) _searchResult->GetCount();
	if (_albumList.GetItemCount() == NULL)
		setCurrentAlbum(NULL);
	_albumList.Invalidate();
	_albumList.UpdateWindow();
	return TRUE;
}

BOOL CAlbumsTab::clearAlbum(void)
{
	if (!_refresh)
		return FALSE;
	if (!_trackList.DeleteAllItems())
		return FALSE;
	_artist.SetWindowText(LABEL_ARTIST_NAME);
	_date.SetWindowText(LABEL_YEAR_NAME);
	_rating.SetWindowText(LABEL_RATING_NAME);
	_price.SetWindowText(LABEL_PRICE_NAME);
	_trackNum.SetWindowText(LABEL_NB_TRACKS_NAME);
	_genre.SetWindowText(LABEL_GENRE_NAME);
	_pic.loadPic(PIC_ALIEN_SMALL);
	return TRUE;
}

void CAlbumsTab::OnPaint()
{
	CPaintDC dc(this); // device context for painting
	if (!_refresh){
		_refresh = TRUE;
		_albumList.SetFocus();
		displayAlbum();
		displayList();
	}
}
/////////////////////////////////////////////////////////////////////////////
// UI related
/////////////////////////////////////////////////////////////////////////////

void CAlbumsTab::OnLvnItemActivateAlbumsList(NMHDR *pNMHDR, LRESULT *pResult)
{
	LPNMITEMACTIVATE pNMIA = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
	*pResult = 0;
	setCurrentAlbum((Album*) _albumList.GetItemData(pNMIA->iItem));
}

void CAlbumsTab::OnLvnColumnclickAlbumsList(NMHDR *pNMHDR, LRESULT *pResult)
{
	static int state = 0;
	LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);

	if (state & (1 << pNMLV->iSubItem))
		_albumList.SortItems(MyCompareProc, pNMLV->iSubItem);
	else
		_albumList.SortItems(MyCompareProcD, pNMLV->iSubItem);

	state ^= (1 << pNMLV->iSubItem);
	*pResult = 0;
}


void CAlbumsTab::OnNMDblclkTracks(NMHDR *pNMHDR, LRESULT *pResult)
{
	if (_currentAlbum == NULL)
		return;
	LPNMITEMACTIVATE pNMIA = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
	_currentAlbum->_matchTrack = pNMIA->iItem;
	_trackList._track = _currentAlbum->_matchTrack;
	_trackList.Invalidate();
	_trackList.UpdateWindow();
	*pResult = 0;
	OnProposal();
	_allTabs->SetActivePage(TAB_ID3);
}
void CAlbumsTab::OnNMRclickList1(NMHDR *pNMHDR, LRESULT *pResult)
{
	if (_currentAlbum == NULL)
		return;
	LPNMITEMACTIVATE pNMIA = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
	_currentAlbum->_matchTrack = pNMIA->iItem;
	_trackList._track = _currentAlbum->_matchTrack;
	_trackList.Invalidate();
	_trackList.UpdateWindow();
	*pResult = 0;
	OnProposal();
	_allTabs->SetActivePage(TAB_ID3);
}


void CAlbumsTab::OnLvnColumnclickTracksList(NMHDR *pNMHDR, LRESULT *pResult) {
	return;
	static int state = 0;
	LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);

//	if (state & (1 << pNMLV->iSubItem))
		_trackList.SortItems(MyCompareTracks, (LPARAM) &_trackList);
//	else
//		_trackList.SortItems(MyCompareTracksD, pNMLV->iSubItem);
	state ^= (1 << pNMLV->iSubItem);
	*pResult = 0;
}

void CAlbumsTab::OnLvnKeydownAlbumList(NMHDR *pNMHDR, LRESULT *pResult)
{
	LPNMLVKEYDOWN pLVKeyDow = reinterpret_cast<LPNMLVKEYDOWN>(pNMHDR);
	*pResult = 0;
	// Select the keys
	int side = 0;
	if (pLVKeyDow->wVKey == VK_DOWN)
		side = 1;
	else if (pLVKeyDow->wVKey == VK_UP)
		side = -1;
	else
		return;
	// Get the item position
	POSITION pos = _albumList.GetFirstSelectedItemPosition();
	if (pos == NULL)
		return;
	int nItem = _albumList.GetNextSelectedItem(pos);
	_albumList.SetItemState(nItem, 0, LVIS_SELECTED);
	if ((nItem + side) >= 0 && (nItem + side) < _albumList.GetItemCount()) {
		nItem += side;
		// Setting the new current album and broadcasting
		setCurrentAlbum((Album*) _albumList.GetItemData(nItem));
	}
	_albumList.SetItemState(nItem, LVIS_SELECTED, LVIS_SELECTED);
}

///////////////////////////////////////////////////////////////////////////
// Match and proposal stuffs
///////////////////////////////////////////////////////////////////////////

void CAlbumsTab::OnTimer(UINT nIDEvent) {
	if (_prefs->_autoSearchData == TRUE && _searching == FALSE && _ID3Tab->setResult(NULL)) {
		if (_currentAlbum == NULL || _currentAlbum->getId() != purifyName(_ID3Tab->_artistData))
			triggerDownload(_ID3Tab->_artistData);
		else {
			_currentAlbum = NULL;
			setSearchReady(_searchResult);
		}
		if (_allTabs->GetActiveIndex() == TAB_ID3) {
			_ID3Tab->OnPaint();
		}
	}
	if (_allTabs->GetActiveIndex() == TAB_COVER)
		_allTabs->downloadBigPic();
	CResizablePage::OnTimer(nIDEvent);
}

int CAlbumsTab::matchAlbum(void) {
	if (_searchResult == NULL || _searchResult->IsEmpty() == TRUE)
		return 0;

	// Some lame variables
	CString purifiedSongName = purifyName(_ID3Tab->getTitleName());
	CString purifiedAlbumName = purifyName(_ID3Tab->_tags._albumData);
	Album *album;
	POSITION pos = _searchResult->GetHeadPosition();
	// Set _matchTrack for every albums
	for (int size = (int) _searchResult->GetCount(), i = 0; i < size; i++) {
		album = _searchResult->GetNext(pos);
		album->_match = -1;
		album->_matchTrack = -1;
		// Match the album
		if (purifyName(album->getTitle()) == purifiedAlbumName) {
			album->_match = MATCH_AVERAGE;
			if ((album->getTitle()).GetLength() == (_ID3Tab->_tags._albumData).GetLength())
				album->_match = MATCH_OK;
		}
		// Match the tracks
		for (int j = 0, len = album->getTracksSize(); j < len; j++) {
			if (purifyName(album->getTracks(j)) == purifiedSongName) {
				album->_matchTrack = j;
				if (album->getTracks(j).GetLength() == (_ID3Tab->getTitleName()).GetLength()) {
					album->_match++;
					break;
				}
			}
		}
		if (album->_matchTrack != -1)
			album->_match++;
	}
	return 1;
}

int CAlbumsTab::selectProposal(void) {
	if (_searchResult == NULL || _searchResult->IsEmpty() == TRUE)
		return 0;

	// Some lame variables
	Album *album;
	CFileFind file;
	POSITION pos = _searchResult->GetHeadPosition();
	int temp = -2;
	_proposalAlbum = NULL;
	_albumList._proposal = "";


	// Set _matchTrack for every albums
	for (int size = (int) _searchResult->GetCount(), i = 0; i < size; i++) {
		album = _searchResult->GetNext(pos);
		if (album->_match > temp) {
			_proposalAlbum = album;
			temp = album->_match;
			_albumList._proposal = album->getAsin();
		}
		else if (album->_match == temp && file.FindFile(album->getImageFile())) { // test me more
			file.Close();
			_proposalAlbum = album;
			temp = album->_match;
			_albumList._proposal = album->getAsin();
		}
		if (album->_match == MATCH_PERFECT && file.FindFile(album->getImageFile())) {
			file.Close();
			break;
		}
	}
	if (temp < 0) {
		_proposalAlbum = _searchResult->GetHead();
		_albumList._proposal = _proposalAlbum->getAsin();
	}
	return 1;
}

#define MIN_SIZE 488
#define LIST_BASE_SIZE 146 // ie winRect.bottom-winRect.top
#define LIST_BASE_TOP 341 // ie winRect.bottom-winRect.top

void CAlbumsTab::OnSize(UINT nType, int cx, int cy)
{
	CResizablePage::OnSize(nType, cx, cy);
	if (_albumList._listAlbum == TRUE) { // have to find something better, bug source-ish
		CRect fullRect;
		this->GetWindowRect(fullRect); // absolute position
		int newSize = 4*(cy - MIN_SIZE) / 5;
		int newSize2 = 1*(cy - MIN_SIZE) / 5;
		_prefs->_heigthData = cy - MIN_SIZE;
		_prefs->_windowTop = fullRect.top;
		_prefs->_windowLeft = fullRect.left;
		_prefs->saveData();

		CRect winRect;
		_trackList.GetWindowRect(&winRect); // absolute position
		_trackList.SetWindowPos(this, winRect.left-fullRect.left, winRect.top-fullRect.top,
			winRect.right-winRect.left, LIST_BASE_SIZE + newSize,
			SWP_NOZORDER | SWP_SHOWWINDOW); // relative position

		_albumList.GetWindowRect(&winRect); // absolute position
		_albumList.SetWindowPos(this, winRect.left-fullRect.left, LIST_BASE_TOP + newSize,
			winRect.right-winRect.left, LIST_BASE_SIZE + newSize2,
			SWP_NOZORDER | SWP_SHOWWINDOW); // relative position
	}
}

#define KEY_STATE_UP 257
BOOL CAlbumsTab::PreTranslateMessage(MSG* pMsg) {
	if(pMsg->wParam == VK_RETURN && pMsg->message == KEY_STATE_UP
		&& _editFind.GetFocus() == _editFind.GetWindow(NULL)) {
			OnBnClickedFind();
	}
	return CResizablePage::PreTranslateMessage(pMsg);
}
void CAlbumsTab::OnLButtonDblClk(UINT nFlags, CPoint point)
{
	_allTabs->OnShowMini();
	CResizablePage::OnLButtonDblClk(nFlags, point);
}

void CAlbumsTab::copyToClipboard()
{
	if (_currentAlbum == NULL)
		return;
	CString text;
	text = _currentAlbum->getArtist() + "\n";
	text += _currentAlbum->getGenre() + "\n";
	text += _currentAlbum->getTitle() + "\n";
	text += _currentAlbum->getDate() + "\n";
	text += "\nTracks:\n";
	for (int i = 0; i < _currentAlbum->getTracksSize(); i++)
		text += _currentAlbum->getTracks(i) + "\n";

	HANDLE hglbCopy = GlobalAlloc(GMEM_DDESHARE,
		(text.GetLength() + 1) * sizeof(TCHAR));

	if (hglbCopy == NULL)
		return;
	strcpy((char *)GlobalLock(hglbCopy), (LPCTSTR)text);
	GlobalUnlock(hglbCopy);
	if (!OpenClipboard())
		return;
	if (!EmptyClipboard())
		return;
	SetClipboardData(CF_TEXT, hglbCopy);
	CloseClipboard();
}
